from copy import copy

def printTree(label, tree):
  print(str(label)+':')
  printBranch(tree, '')

def printBranch(tree, spacing):
#  s=spacing+str(tree[0])+','+str(stripDict(tree[1]))+': '
  s=spacing
  item=tree[2]
  ftype=item[0]
  if ftype=='literal':
    s=' '*len(s) # don't print context, it doesn't matter for literals
    print(s+str(item[1]))
  elif ftype=='symdef':
    print(s+str(':'+str(item[1])))
  elif ftype=='symref':
    print(s+str('$'+str(item[1])))
  elif ftype=='symref':
    print(s+str('$'+str(item[1])))
  elif ftype=='func':
    print(s+str(item[1][0]))
    args=item[1][1]
    for arg in args:
      printBranch(arg, spacing+'  ')
  elif ftype=='native':
    print(s+'!'+str(item[1][0]))
    args=item[1][1]
    for arg in args:
      printBranch(arg, spacing+'  ')
  elif ftype=='block':
    if len(item[1]['params'])>0:
      print(s+'{ '+str(item[1]['params']))
    else:
      print(s+'{')
    printBranch(tuplifyTree(tree[0], tree[1], item[1]['code']), spacing+'  ')
    print(spacing+'}')
  else:
    print(s+'?')

def stripDict(om):
  nm={}
  for key in om:
    key=str(key)
    value=om[key]
    nm[key]=value[2][1]
  return nm

def tuplifyTree(lex, dyn, tree):
  if type(tree)==tuple:
    lex, dyn, item=tree
  else:
    item=tree

  ftype=item[0]

  if ftype=='literal' or ftype=='symref' or ftype=='symdef' or ftype=='block':
    return (lex, dyn, item)
  elif ftype=='native' or ftype=='func':
    fname=item[1][0]
    fargs=item[1][1]

    args=copy(fargs)
    for x in range(len(args)):
      args[x]=tuplifyTree(lex, dyn, args[x])
    item=[ftype, [fname, args]]
    return (lex, dyn, item)
  else:
    print('Unsupported: '+str(ftype)+' '+str(item))

def checkNative(branch):
  lex, dyn, code=branch

  ftype=code[0]

  return ftype=='native'

def checkResolved(branch):
  lex, dyn, code=branch

  ftype=code[0]
  fname=code[1][0]
  fargs=code[1][1]

  for arg in fargs:
    argLex, argDyn, arg=arg
    argType=arg[0]
    if argType!='literal' and argType!='block' and argType!='symdef':
      return False

  return True

def checkLiteral(branch):
  if not branch:
    return True

  lex, dyn, code=branch

  ftype=code[0]

  return ftype=='literal'

def lookup(system, userlib, lex, dyn, fname):
  if fname in system:
    return system[fname]
  elif fname in userlib:
    return userlib[fname]
  elif fname in lex:
    return lex[fname]
  elif fname in dyn:
    return dyn[fname]
  else:
    print('Not found: '+str(fname))
    return None

def lookupFunction(system, userlib, lex, dyn, fname, fargs):
  if fname in system:
    f=system[fname]
    if f['type']=='native':
      return f
    else:
      print('Unsupported function!')
  elif fname in userlib:
    f=userlib[fname]
    return f
  elif fname in lex:
    print('lex!')
    f=lex[fname]
    return f
  elif fname in dyn:
    print('dyn!')
    f=dyn[fname]
    return f
  else:
    print('Not found: '+str(fname))
    return None

def stripLiterals(items):
  return [item[2][1] for item in items]
